void Main()
{
var game = new GameState
{
playerHitPoints = 50,
playerMana = 500,
bossDamage = 10,
bossHitPoints = 71,
spellStates = new(),
};
var part1 = game.PlayerPlays()
.Where(p => p.playerHitPoints > 0)
.OrderBy(p => p.playerManaSpent)
.First();
part1.playerManaSpent.Dump();
var part2 = game.PlayerPlays(true)
.Where(p => p.playerHitPoints > 0)
.OrderBy(p => p.playerManaSpent)
.First();
part2.playerManaSpent.Dump();
}
public class GameState
{
public int playerManaSpent;
public int playerHitPoints;
public int playerDamage;
public int playerMana;
public int playerArmor;
public int bossHitPoints;
public int bossDamage;
public Dictionary spellStates;
}
static class Helpers
{
static GameState Clone(this GameState gameState)
{
return new GameState
{
playerManaSpent = gameState.playerManaSpent,
playerHitPoints = gameState.playerHitPoints,
playerDamage = gameState.playerDamage,
playerMana = gameState.playerMana,
playerArmor = gameState.playerArmor,
bossHitPoints = gameState.bossHitPoints,
bossDamage = gameState.bossDamage,
spellStates = gameState.spellStates.ToDictionary(s => s.Key, s => s.Value),
};
}
static void CastSpell(this GameState gameState, Spell spell)
{
gameState.playerMana -= spell.Cost;
gameState.playerManaSpent += spell.Cost;
gameState.spellStates[spell] = spell.Timer;
spell.Cast(gameState);
}
static bool IsOver(this GameState gameState) =>
gameState.bossHitPoints <= 0 || gameState.playerHitPoints <= 0;
public static bool CanCast(this GameState state, Spell spell) =>
state.playerMana >= spell.Cost && (!state.spellStates.TryGetValue(spell, out var s) || s == 0);
public static IEnumerable PlayerPlays(this GameState gameState, bool hardMode = false)
{
if (hardMode)
gameState.playerHitPoints--;
gameState.ApplySpells();
foreach (var spell in Spells.Where(s => gameState.CanCast(s)))
{
var cloned = gameState.Clone();
cloned.CastSpell(spell);
if (cloned.IsOver())
yield return cloned;
else
{
cloned.BossPlays();
if (cloned.IsOver())
yield return cloned;
else
foreach (var s in cloned.PlayerPlays(hardMode))
yield return s;
}
}
}
static void BossPlays(this GameState gameState)
{
gameState.ApplySpells();
if (gameState.bossHitPoints > 0)
gameState.playerHitPoints -= (gameState.bossDamage - gameState.playerArmor);
}
static void ApplySpells(this GameState gameState)
{
foreach (var spell in gameState.spellStates.Where(s => s.Value > 0).Select(s => s.Key))
{
gameState.spellStates[spell]--;
spell.Assess(gameState, spell);
}
}
}
public class Spell
{
public int Timer { get; set; }
public int Cost { get; set; }
public Action Cast = _ => { };
public Action Assess = (_, _) => { };
}
public static List Spells = new()
{
new Spell
{
// Magic Missile
Cost = 53,
Cast = state => state.bossHitPoints -= 4
},
new Spell
{
// Drain
Cost = 73,
Cast = state =>
{
state.bossHitPoints -= 2;
state.playerHitPoints += 2;
}
},
new Spell
{
// Shield
Cost = 113,
Timer = 6,
Cast = state => state.playerArmor = 7,
Assess = (state, spell) => state.playerArmor = state.spellStates[spell] == 0 ? 0 : state.playerArmor
},
new Spell
{
// Poison
Cost = 173,
Timer = 6,
Assess = (state, spell) => state.bossHitPoints -= 3
},
new Spell
{
// Recharge
Cost = 229,
Timer = 5,
Assess = (state, spell) => state.playerMana += 101
},
};